#include <rpc_root.h>
#include <memory>
#include "mock_transport.h"
#include "mock_caller.h"
#include "mock_logger.h"
#ifdef min
#undef min
#endif
#include <cxxopts.hpp>
#include <knet.h>
#include <list>
#include <iostream>

using CallerList = std::list<MockCaller*>;
CallerList callerList;
std::unique_ptr<rpc::RpcImpl> rpc_impl;

void connector_cb(kchannel_ref_t* channel, knet_channel_cb_event_e e) {
    if (!rpc_impl) {
        abort();
    }
    if (e & channel_cb_event_connect) {
        std::cout << "connected" << std::endl;
        auto ptr = rpc::make_shared_ptr<MockTrans>(channel);
        auto* callerPtr = new MockCaller();
        callerList.push_back(callerPtr);
        callerPtr->doTest(ptr, rpc_impl.get());
    }
    else if (e & channel_cb_event_recv) {
        auto ptr = rpc::make_shared_ptr<MockTrans>(channel);
        //rpc::onMessage(ptr);
        rpc_impl->onMessage(std::dynamic_pointer_cast<rpc::Transport>(ptr));
    }
}

int main(int argc, const char** argv) {
    rpc_impl = std::make_unique<rpc::RpcImpl>();

    cxxopts::Options option("proxy");
    option.add_options()
        ("h,host", "Host IP", cxxopts::value<std::string>())
        ("p,port", "Host port", cxxopts::value<int>());
    auto result = option.parse(argc, argv);
    std::string ip;
    int port;
    if (!result["host"].count()) {
        std::cerr << "Need host IP" << std::endl;
        std::cerr << option.help();
        return 0;
    }
    ip = result["host"].as<std::string>();
    if (!result["port"].count()) {
        std::cerr << "Need host port" << std::endl;
        std::cerr << option.help();
        return 0;
    }
    port = result["port"].as<int>();
    MockLogger logger;

    rpc_impl->initialize(&logger);

    auto* loop = knet_loop_create();
    kchannel_ref_t* connector = knet_loop_create_channel(loop, 1024, 1024 * 256);
    knet_channel_ref_set_cb(connector, connector_cb);
    knet_channel_ref_connect(connector, ip.c_str(), port, 10);
    for (;;) {
        knet_loop_run_once(loop);
        rpc_impl->update();
        for (auto& caller : callerList) {
            caller->doTest(nullptr, rpc_impl.get());
        }
    }
    return 0;
}
